
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;


public class Mailer extends JFrame {

	
	// Variables declaration 
	private JLabel emailFromLabel;
	//private JButton startButton;
	//private JButton stopButton;
	//private JProgressBar progressBar;
	private JTextArea textLogs;
	private JTextField emailFromServer;

    private DatabaseInitTask databaseInitTask;
    private SendMailTask sendMailTask;
    
	private DataSource dataSource;
	private SendMail sendMail;
	private boolean proceed;
	private String defaultServer;
	private String from;
	private int queueSize;
	private int totalEmailsSent = 0;
	private int totalEmailsSentOK = 0;

	private final static String newline = "\n";
	
	
    private class DatabaseInitTask extends SwingWorker<Integer, Void> {
        @Override
        protected Integer doInBackground() throws Exception {
        	int queueSize = dataSource.getQueueSize();
            return queueSize;
        }

        @Override
        public void done() {           
            try {
            	//startButton.setEnabled(true);
            	queueSize = get();
            	//progressBar.setMaximum(queueSize);
            	textLogs.append("Connection OK."+newline+"-------------"+newline+
            			"Emails to send: "+queueSize+newline+"-------------"+newline);
            	//if (queueSize==0) {
            		//startButton.setEnabled(false);
            	//}
            } catch (Exception e) {
            	textLogs.append("Problems connecting to the DataBase."+newline);
            	textLogs.append(e.toString());
            	//startButton.setEnabled(false);
            }
        }

    }
    
	private class LogAndProgress {
		private String logString;
		private Boolean mailSent;
		
		public LogAndProgress(String logString, Boolean mailSent) {
			this.logString = logString;
			this.mailSent = mailSent;
		}
	}
    
    private class SendMailTask extends SwingWorker<String, LogAndProgress> {
        @Override
        protected String doInBackground() throws Exception {
        	try {         		
        		boolean loop = true;
        		while (loop) {      
        			//System.out.println("restarting loop..." + dataSource);
	        		while (dataSource.nextTopMessage()) {  
	        			
	        			publish(new LogAndProgress("TopMessage with id ["+
	        					dataSource.getTopMessage().getId()+"] fetched."+newline, null));
	        		
	    	    		while (dataSource.nextGroupForTopMessage()) {
	    	    			publish(new LogAndProgress("> Next Emails Group with size ["+
	    	    					dataSource.getEmailQueue().size()+"] fetched."+newline, null));
	    		    		for (int i=0; i<dataSource.getEmailQueue().size();i++) {
	    		    			try {
	    		    				sendMail.send((String)dataSource.getEmailQueue().get(i), 
	    		    						(String)dataSource.getTopMessage().getSubject(), (String)dataSource.getTopMessage().getBody());
	    		    				publish(new LogAndProgress("    [OK] "+(String)dataSource.getEmailQueue().get(i)+newline, true));    		    				
	    		    			} catch (Exception e) {
	    		    				String errorMsg, errorStatus = "";
	    		    				if (e.getCause()!=null) { //real nested errors
	    		    					errorMsg = e.getCause().getMessage();
	    		    				} else { //rejected by smtp -- sleep a bit here (30s)
	    		    					Thread.sleep(30000);
	    		    					errorMsg = e.getMessage()+newline;
	    		    				} 
	    		    				System.out.println(e.toString());
	    		    				
	    		    				/* 
	    		    				 * Pattern matching for the sending Error Code
	    		    				 */
	    		    				
	    		    				/*Pattern pattern = Pattern.compile("450 4.7.1"); //tooManyMails 
	    		    				Matcher matcher = pattern.matcher(e.toString());    		    				
	    		    				if (matcher.find()) {
	    		    					Exception ne = waitAndResend(0, (String)dataSource.getEmailQueue().get(i),
	    	    		    					(String)dataSource.getTopMessage().getSubject(), (String)dataSource.getTopMessage().getBody());
	    		    					if (ne!=null) {
	    		    						e= ne; //first problem solved --slowlyness, now lets see further
	    		    					}
	    		    				}  
	    		    				    		    				
		    		    			pattern = Pattern.compile("450 4.1.2");  //Domain not Found		    				    		    				
		    		    			matcher = pattern.matcher(e.toString());
		    		    			if (matcher.find()) {errorCode = 450412; errorMsg = ":INVALID"; } */
		    		    			
		    		    			dataSource.addFailedEmail((String)dataSource.getEmailQueue().get(i));
		    		    			publish(new LogAndProgress("   [NOK"+errorStatus+"] "+ errorMsg, false));
		    		    			
		    		    			/*switch (errorCode) {
		    		    				case 450412: /* Put the mail in the invalid list not the failed one */;
		    		    			/*}*/
		    		    			
	    		    				/* 
	    		    				 * End Pattern matching
	    		    				 */
	    		    			}
	    		    			
	    		    			dataSource.addTreatedEmail((String)dataSource.getEmailQueue().get(i));
	    		    			
			    				if (isCancelled()) {
			    					dataSource.clearActiveGroupFromQueue();
			    					dataSource.close();
			    					return null;
			    				}    		    					    			
	    		    		}
	    		    		dataSource.clearActiveGroupFromQueue();
	    		    		publish(new LogAndProgress("    "+"> Active Group cleared."+newline, null));
	    	    		}    		
	    	    		publish(new LogAndProgress("-------------"+newline, null));
	        		}
	        		loop = dataSource.resetFailedEmails();
	        		//System.out.println("calculated loop: " + loop);
	        		publish(new LogAndProgress("-------------"+newline+"Failed Emails Reset."+newline, null));
        		}      
        		return "";
        	} catch (Exception e) {
        		System.out.println(e.toString());
        		publish(new LogAndProgress("Problems sending emails."
            			+newline+e.toString()+newline+"-------------"+newline, null));
        		throw e;
        	}
        	
        }
        
        /*
        private Exception waitAndResend(int level, String email, String subject, String body) {
        	try {        
        		level++;
        		publish(new LogAndProgress("   [NOK] Go to sleep for "+level*5+" sec"+newline, false));
        		Thread.sleep(5000*level);
        		publish(new LogAndProgress("   [NOK] Wake Up... Retry!"+newline, false));        		
				sendMail.send(email, subject, body);
				return null;
			} catch (Exception e) {
				Pattern pattern = Pattern.compile("450 4.7.1"); //tooManyMails
				Matcher matcher = pattern.matcher(e.toString());
				//if the slowlyness persist
				if (matcher.find()) {  
					return waitAndResend(level, email, subject, body);					
				} else {
					//it's some other problem
					return e;
				}
			}
        }*/

        @Override
        protected void process(List<LogAndProgress> pairs) {
        	LogAndProgress pair;
        	for (int i=0; i<pairs.size(); i++) {
        		pair = pairs.get(i);
        		textLogs.append(pair.logString);
        		if (pair.mailSent!=null) {
        			//progressBar.setValue(progressBar.getValue()+1);
        			totalEmailsSent++;
        			if (pair.mailSent) {
        				totalEmailsSentOK++;
        			} 
        		}
        	}
        }
        
        @Override
        public void done() {                       	
            	try {     					
					textLogs.append(get());
					textLogs.append(totalEmailsSentOK+ " Sent Emails [OK] from a Total of "
							+totalEmailsSent+" Emails");
					totalEmailsSent = 0;
					totalEmailsSentOK = 0; //reset counters
					//startButton.setEnabled(true);
					//stopButton.setEnabled(false);
				}  catch (Exception e) {
					System.out.println(e.toString());
					//textLogs.append(e.toString());
				}
        }

    }

    private class SaveBeforeClose extends WindowAdapter {
        public void windowClosing( WindowEvent e ) {
			try {
				//System.out.println(dataSource.hasCon());
				//to test later!
				if ( (dataSource.hasCon()) /*&& !startButton.isEnabled()*/ ) {				
					dataSource.clearActiveGroupFromQueue();
					dataSource.close();
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
            System.exit( 0 );
            
        }
    }
	
	/* Constructor */
    public Mailer() {
        initComponents();
        
        addComponents();
        
        pack();
        
        Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
		this.setLocation(dim.width/2-this.getWidth()/2,	dim.height/7);
		this.setSize(new Dimension(650,700));	
		addWindowListener( new SaveBeforeClose() );
		
		initDatabase();
        
		sendMail.setServer(defaultServer);
    	sendMail.setFrom(emailFromServer.getText());
    	
    	(sendMailTask = new SendMailTask()).execute();
    }    
    
    private void initComponents() {
    	
    	DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    	Date date = new Date();    	
    	
    	defaultServer = "mail-out.telenet.be";
    	//defaultServer = "uit.telenet.be";
    	from = "EPP AutoBelgium <autobelgium+offerOfTheDay-"+dateFormat.format(date)+"@gmail.com>";
    	System.out.println(from);
    	
    	proceed = true;
    	
        emailFromLabel = new JLabel("Address From");        
        emailFromServer = new JTextField(45);
        emailFromServer.setText(from);
        
        //startButton = new JButton();
        //stopButton = new JButton();
        
        sendMail = new SendMail();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Queue Mailer v1.2");
        
        /*startButton.setText("Start!");
        //startButton.setEnabled(false);
        //startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                startButtonActionPerformed(evt);
            }
        });
        
        stopButton.setText("Stop");
        stopButton.setEnabled(false);
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
        });*/

        /*progressBar = new JProgressBar(0, 100);
        progressBar.setValue(0);
        progressBar.setStringPainted(true);*/
        
        textLogs = new JTextArea();
        


    }
    
    private void addComponents() {
	    	JPanel topPane = new JPanel();
	    		topPane.add(emailFromLabel);
	    		topPane.add(emailFromServer);	    		    		 
	    		topPane.add(Box.createRigidArea(new Dimension(0,30)));
    			//topPane.add(startButton);
    			//topPane.add(stopButton); 	    		
   	
    	add(topPane, BorderLayout.PAGE_START);
			JScrollPane scrollPane = new JScrollPane(textLogs); 
	    	textLogs.setEditable(false);    	
    	add(scrollPane,BorderLayout.CENTER);
    	//add(progressBar, BorderLayout.PAGE_END);
    }

    private void initDatabase() {
    	textLogs.append("Connecting to the DataBase..."+newline);
        dataSource = new DataSource(
        		"jdbc:mysql://mysql.netfirms.com:3306/d60454908", 
        			"u70514128", "2aee82");   
        try {
        	//queueSize = dataSource.init();
        	(databaseInitTask = new DatabaseInitTask()).execute();
        	
        } catch (Exception e) {
        	textLogs.append("Problems connecting to the DataBase.");
        	//startButton.setEnabled(false);
        }
        
    }
    
    /*private void startButtonActionPerformed(ActionEvent evt) {
		//startButton.setEnabled(false);
		//stopButton.setEnabled(true);
    	sendMail.setServer(smtpServer.getText());
    	sendMail.setFrom(from);
    	
    	(sendMailTask = new SendMailTask()).execute();
    	

    }
    
    private void stopButtonActionPerformed(ActionEvent evt) {
    		sendMailTask.cancel(true);
    		sendMailTask = null;
    		//startButton.setEnabled(true);
    		//stopButton.setEnabled(false);
    		textLogs.append(newline+"-------------"+newline+
    					"Prematurely canceled!"+newline+"-------------"+newline+newline);
    }*/
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Mailer().setVisible(true);
            }
        });
    }   

}
